local sim_world = Game:addState("sim_world")

function sim_world:enteredState()
	print("entering sim world")

	self.resources = {}

	--self.resources[#self.resources+1] = Resource:new(0, 0, "water")
	--self.resources[#self.resources+1] = Resource:new(0, 8, "soil")

	self.camera = Camera:new()
	self.width = 32
	self.height = 32
	self.depth = 64
	self.current_map = 1
	self.tile_size = 16
	self.tiles_received = false
	self.rx_tiles = love.thread.getChannel("serial_tiles")
	self.maps = {}

	self.color_plant = {21, 86, 17}
	self.color_soil = {114, 67, 13}
	self.color_water = {42, 47, 142}

	self.time = {}
	self.time.unit = 0.5
	self.time.second = self.time.unit * 4
	self.time.minute = self.time.second * 60
	self.time.hour = self.time.minute * 60
	self.time.day = self.time.hour * 24
	self.time.week = self.time.day * 7
	self.time.month = self.time.week * 4
	self.time.year = self.time.month * 12
	self.time.current = 0
	self.time.factor = 10
	self.time.years = 0
	self.time.months = 0
	self.time.weeks = 0
	self.time.days = 0
	self.time.hours = 0
	self.time.minutes = 0
	self.time.seconds = 0
	self.time.units = 0
	self.time.update = function(self, dt)
		self.time.current = self.time.current + self.time.unit
		if self.time.current >= self.time.unit then
			self.time.current = 0
			self.time.units = self.time.units + 1*self.time.factor
		end

		if self.time.units >= self.time.second/self.time.unit then
			self.time.units = 0
			self.time.seconds = self.time.seconds+1*self.time.factor
		end
		if self.time.seconds >= self.time.minute/self.time.second then
			self.time.seconds = 0
			self.time.minutes = self.time.minutes+1*self.time.factor
		end
		if self.time.minutes >= self.time.hour/self.time.minute then
			self.time.minutes = 0
			self.time.hours = self.time.hours+1
			self:hour_update()
		end
		if self.time.hours >= self.time.day/self.time.hour then
			self.time.hours = 0
			self.time.days = self.time.days+1
			self:day_update()
		end
		if self.time.days >= self.time.week/self.time.day then
			self.time.days = 0
			self.time.weeks = self.time.weeks+1
		end
		if self.time.weeks >= self.time.month/self.time.week then
			self.time.weeks = 0
			self.time.months = self.time.months+1
		end
		if self.time.months >= self.time.year/self.time.month then
			self.time.months = 0
			self.time.years = self.time.years+1
		end
	end
	
	
	self.camera:newLayer(1, function()
		love.graphics.setColor(255, 255, 255)
		love.graphics.print(tostring(self.fps), self.camera.x_zero+(self.camera.width*0.9)*self.camera.scaleX, self.camera.y_zero+(self.camera.height*0.9)*self.camera.scaleY)
		love.graphics.setColor(255,255,255)
		end)
	
	self.camera:newLayer(0.75, function()
		game:main_draw()	
		end)
	self.camera:newLayer(1, function()
		game:cursor_draw()
		end)

	self.camera:newLayer(1, function()
		game:hud_draw()
		end)
	
	self:generate()
	

end

function sim_world:draw()
	
	self.camera:draw_layers()
		
end





function sim_world:set_level(level)
	print("setting level to " .. level)
	self.current_map = level
	self.resources = {}
	if self.maps[self.current_map] then

		for y = 1, self.height do
			if self.maps[self.current_map][y] then
				for x = 1, self.width do
					if self.maps[self.current_map][y][x] then
						local id = #self.resources+1
						self.maps[self.current_map][y][x].id = id
						self.resources[id] = Resource:new(x*self.tile_size, y*self.tile_size, self.maps[self.current_map][y][x].resource, 
							self.maps[self.current_map][y][x].res_count )						
					end
				end
			end
		end
	end

	for i = 1, #self.resources do
		self.resources[i]:adapt_surrounding_tiles()
	end
end

function sim_world:main_draw()

	for i = 1, #self.resources do
		self.resources[i]:draw()
		
	end
	love.graphics.setColor(255,255,255)
	--love.graphics.setColor(255,255,0)
	--love.graphics.rectangle("fill", 10, 10, 8, 8)
	--love.graphics.setColor(255,255,255)
	


end

function sim_world:hud_draw()
	local x = (self.camera.x_max-200)*self.camera.scaleX
	local y = (self.camera.y_zero+100)*self.camera.scaleY

	if self.player.hover_tile then
		
		love.graphics.print(self.player.hover_tile.resource, x, y)
		love.graphics.print(self.player.hover_tile.res_count, x, y+20)
		if self.player.hover_tile.id then
			if self.resources[self.player.hover_tile.id] then
				if self.resources[self.player.hover_tile.id].surrounding_tiles then
					if self.resources[self.player.hover_tile.id].surrounding_tiles.ul then
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.ul.resource, x-40, y-40) 
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.ul.res_count, x-40, y-20)
					end
					if self.resources[self.player.hover_tile.id].surrounding_tiles.u then
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.u.resource, x, y-40) 
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.u.res_count, x, y-20) 
					end
					if self.resources[self.player.hover_tile.id].surrounding_tiles.ur then
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.ur.resource, x+40, y-40) 
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.ur.res_count, x+40, y-20) 
					end
					if self.resources[self.player.hover_tile.id].surrounding_tiles.r then
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.r.resource, x+40, y) 
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.r.res_count, x+40, y+20) 
					end
					if self.resources[self.player.hover_tile.id].surrounding_tiles.l then
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.l.resource, x-40, y) 
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.l.res_count, x-40, y+20) 
					end
					if self.resources[self.player.hover_tile.id].surrounding_tiles.dl then
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.dl.resource, x-40, y+40) 
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.dl.res_count, x-40, y+60) 
					end
					if self.resources[self.player.hover_tile.id].surrounding_tiles.d then
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.d.resource, x, y+40) 
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.d.res_count, x, y+60) 
					end
					if self.resources[self.player.hover_tile.id].surrounding_tiles.dr then
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.dr.resource, x+40, y+40) 
						love.graphics.print(self.resources[self.player.hover_tile.id].surrounding_tiles.dr.res_count, x+40, y+60) 
					end
				end
			end
		end

	end
	--[[
	local base_t = self.time.current/self.time.year
	local ty = math.floor(base_t)
	local tm = math.floor(math.fmod(self.time.current, self.time.year)/self.time.month)
	local tw = math.floor(math.fmod(self.time.current, self.time.month)/self.time.week)
	local td = math.floor(math.fmod(self.time.current, self.time.week)/self.time.day)
	local th = math.floor(math.fmod(self.time.current, self.time.day)/self.time.hour)
	local tm2 = math.floor(math.fmod(self.time.current, self.time.hour)/self.time.minute)
	local ts = math.floor(math.fmod(self.time.current, self.time.minute)/self.time.second)
	]]
	love.graphics.print( self.time.years .. " years, ".. self.time.months .. " months, " .. 
		self.time.weeks .. " weeks, " .. self.time.days .. " days, " .. self.time.hours .. 
		" hours, " .. self.time.minutes .. " minutes, " .. self.time.seconds .. " seconds.", 
		
		(self.camera.x_zero+10)*self.camera.scaleX, 
		(self.camera.y_max-40)*self.camera.scaleY)

	

end

function sim_world:cursor_draw()
	local tile
	if self.resources then
		local x, y = love.mouse.getPosition()
		
	 	tile = self:get_tile(x,y)
	end

	if tile then
		--print("tile found drawing at " .. tile.x*self.tile_size .. " " .. tile.y*self.tile_size)
		love.graphics.setColor(255, 0, 0)
		love.graphics.rectangle("line", (tile.x)*self.tile_size-self.tile_size, (tile.y)*self.tile_size-self.tile_size, self.tile_size*3*self.camera.scaleX, self.tile_size*3*self.camera.scaleY)
		love.graphics.setColor(255,255,255)
		self.player.hover_tile = tile
	end

end

function sim_world:hour_update()
	
end

function sim_world:day_update()
	collectgarbage()
	--self:do_to_all_resources(function(res) res:get_surrounding_tiles()	end)
end

function sim_world:update(dt)
	
	self.fps = love.timer.getFPS()
	self:check_channels(dt)
	self.camera:update(dt)	
	game.time.update(self)
	
end

function sim_world:get_tile(x, y)
	local x = math.floor((x/(self.tile_size)*self.camera.scaleX))
	local y = math.floor((y/(self.tile_size)*self.camera.scaleY))
	--print(x .. " " .. y)
	local tile
	if self.maps[self.current_map] then
		if self.maps[self.current_map][y] then
			if self.maps[self.current_map][y][x] then
				tile = self.maps[self.current_map][y][x]
			end
		end
	end
	if tile then
		--print(tile.resource .. " tile selected")
		return tile
	else
		--print("tile not found")
		return nil
	end

	
end

function sim_world:get_resource(x, y)
	 local x = math.floor((x/(self.tile_size)*self.camera.scaleX))
	 local y = math.floor((y/(self.tile_size)*self.camera.scaleY))


	for i = 1, #self.resources do
		if self.resources[i].x == x and self.resources[i].y == y then
			return self.resources[i]
		end
	end
end

function sim_world:do_to_all_resources(func)
	for i = 1, #self.resources do
		func(self.resources[i])
	end
end

function sim_world:check_channels(dt)

	local serial_tiles
	if not self.tiles_received then
		serial_tiles = self.rx_tiles:pop()
	end

	if serial_tiles and not self.tiles_received then
		
		print("receiving tiles")
		self.maps = {}
		local x, y, z = 0, 1, 1
		local finished = false
		for i = 1, #serial_tiles do
			x = x + 1
			if x > self.width then
				x = 0
				y = y + 1
				if y > self.height then
					y = 0
					z = z + 1
					if z > self.depth then
						finished = true
					end
				end
			end
			if not finished then
				if not self.maps[z] then self.maps[z] = {} end
				if not self.maps[z][y] then self.maps[z][y] = {} end
				if not self.maps[z][y][x] then self.maps[z][y][x] = {} end
				if serial_tiles[i] == 0 then
					self.maps[z][y][x].resource = "water"
				elseif serial_tiles[i] == 1 then
					self.maps[z][y][x].resource = "soil"
				elseif serial_tiles[i] == 2 then
					self.maps[z][y][x].resource = "plant"
				end
				self.maps[z][y][x].x = x
				self.maps[z][y][x].y = y
				self.maps[z][y][x].z = z
				self.maps[z][y][x].res_count = love.math.random(100)
			end
		end
		self.map_generator = nil
		self.map_generator_fd = nil
		self.tiles_received = true
		self:set_level(1)		
	end


end

function sim_world:generate()

	local generate = 
	[[  require'love.filesystem'
		require'love.math'
		class = require'lib.middleclass'
		Stateful = require'lib.stateful'
		local map = class('map')
		print("in map generator thread")

		function map:initialize()
			self.width =]] .. self.width .. [[
			self.height =]] .. self.height .. [[
			self.depth =]] .. self.depth .. [[
			self.wall_type = "soil"
			self.floor_type = "water"
			self.space_type = "plant"
			self.map = {}
		end

		function map:generate()
			print("map generating")
			for z = 1, self.depth do
				if not self.map[z] then self.map[z] = {} end
				self.map[z]={}
				self.map[z] = self:gen()
			end

			print("map generated")

		end

		function map:gen( reps, reps2 )

			local reps = reps or 5
			local reps2 = reps2 or 3
			self.layout = {}
			for y = 1, self.height do
				self.layout[y] = {}
				for x = 1, self.width do

					local r = love.math.random(100)

					if r < 45 then
						self.layout[y][x] = self.wall_type
					else
						self.layout[y][x] = self.floor_type
					end

				end
			end

			for i = 1, reps do
				for y = 1, #self.layout do			
					for x = 1, #self.layout[y] do

						local z = self:surrounding_walls(x, y, 1, 1)
						local q = self:surrounding_walls(x, y, 2, 2)

						if z > 5 then self.layout[y][x] = self.wall_type end
						if q < 2 then self.layout[y][x] = self.wall_type end

					end
				end
			end

			for i = 1, reps2 do
				for y = 1, self.height do
					for x = 1, self.width do
						local z = self:surrounding_walls(x, y, 1, 1)
						local q = self:surrounding_walls(x, y, 2, 2)

						if z > 5 then self.layout[y][x] = self.wall_type end

						self:surrounding_diagonals(x, y)

					end
				end
			end
			
			-- see junk.lua

			return self.layout
		end

		function map:surrounding_walls(x, y, distX, distY)

			local distX = distX or 1
			local distY = distY or 1
			local walls = 0


			if distX == 1 and distY == 1 then
				if self.layout[y][x] then			
					if self.layout[y-1] then
						if self.layout[y-1][x] then
							if self.layout[y-1][x] == self.wall_type then walls = walls+1 end
						end
						if self.layout[y-1][x+1] then
							if self.layout[y-1][x+1] == self.wall_type then walls = walls+1 end
						end
						if self.layout[y-1][x-1] then
							if self.layout[y-1][x-1] == self.wall_type then walls = walls+1 end
						end
					end
					if self.layout[y][x+1] then
						if self.layout[y][x+1] == self.wall_type then walls = walls+1 end
					end
					if self.layout[y][x-1] then
						if self.layout[y][x-1] == self.wall_type then walls = walls+1 end
					end
					if self.layout[y+1] then
						if self.layout[y+1][x] then
							if self.layout[y+1][x] == self.wall_type then walls = walls+1 end
						end
						if self.layout[y+1][x+1] then
							if self.layout[y+1][x+1] == self.wall_type then walls = walls+1 end
						end						
						if self.layout[y+1][x-1] then
							if self.layout[y+1][x-1] == self.wall_type then walls = walls+1 end
						end
					end
					
					
				end
			else
				for y1 = 1, distY do
					for x1 = 1, distX do
						local tile, tile2
						if self.layout[y+y1-1] then
							if self.layout[y+y1-1][x+x1-1] then
								tile = self.layout[y+y1-1][x+x1-1]
							end
						end
						if self.layout[y-y1] then
							if self.layout[y-y1][x-x1] then
								tile2 = self.layout[y-y1][x-x1]
							end
						end

						if tile == self.wall_type then walls = walls+1 end
						if tile2 == self.wall_type then walls = walls+1 end
					end
				end
			end

			return walls

		end

		function map:surrounding_diagonals(x, y)

			if self.layout[y][x] == self.wall_type then

				local ul, ur, u, bl, br, b, l, r
					if self.layout[y-1] then
						if self.layout[y-1][x-1] then
							ul = self.layout[y-1][x-1]
						end
						if self.layout[y-1][x+1] then					
							ur = self.layout[y-1][x+1]
						end
						if self.layout[y-1][x] then
							u = self.layout[y-1][x]
						end
					end
					if self.layout[y+1] then
						if self.layout[y+1][x-1] then
							bl = self.layout[y+1][x-1]
						end
						if self.layout[y+1][x+1] then
							br = self.layout[y+1][x+1]
						end
						if self.layout[y+1][x] then
							b = self.layout[y+1][x]
						end
					end

					if self.layout[y][x-1] then			
						l = self.layout[y][x-1]
					end
					if self.layout[y][x+1] then
						r = self.layout[y][x+1]
					end
					
					

					if l == self.floor_type and 
						u == self.floor_type and 
						r == self.floor_type then
						self.layout[y][x] = self.floor_type
					end

					if l == self.floor_type and
						lo == self.floor_type and
						r == self.floor_type then
						self.layout[y][x] = self.floor_type
					end

					if (ul == self.wall_type or ul == self.space_type ) and
						(ur == self.wall_type or ur == self.space_type) and
						(bl == self.wall_type or bl == self.space_type) and
						(br == self.wall_type or br == self.space_type) and
						(l == self.wall_type or l == self.space_type) and
						(r == self.wall_type or r == self.space_type) and
						(u == self.wall_type or u == self.space_type) and
						(b == self.wall_type or b == self.space_type) then
						self.layout[y][x] = self.space_type
					end


			end

		end

		function map:serialize_tiles()
			print("serializing tiles")
			local ser = {}
			for z = 1, #self.map do
				for y = 1, #self.map[z] do
					for x = 1, #self.map[z][y] do
						local tile = self.map[z][y][x]
						if tile == "water" then
							ser[#ser+1] = 0
						elseif tile =="soil" then
							ser[#ser+1] = 1
						elseif tile == "plant" then
							ser[#ser+1] = 2
						end
					end
				end
			end

			self.serial_tiles = ser
		end

		function map:channel_tiles()
			print("sending tiles")
			local tx_tiles = love.thread.getChannel("serial_tiles")
			tx_tiles:push(self.serial_tiles)

		end

		local CellAutoMap = map:new()

		CellAutoMap:generate()
		CellAutoMap:serialize_tiles()
		CellAutoMap:channel_tiles()

		]]

	self.map_generator_fd = love.filesystem.newFileData(generate, "mg.lua", "file")
	
	self.map_generator = love.thread.newThread(self.map_generator_fd)
	print("starting map generator")
	self.map_generator:start()


end

function sim_world:exitedState()
	print("exiting sim world")
end
